Skip to content

大家好,我是农村程序员,独立开发者,行业观察员,前端之虎陈随易。

如果本文能给你提供启发或帮助,欢迎动动小手指,一键三连 (点赞、评论、转发),给我一些支持和鼓励,谢谢。


犹抱琵琶半遮面,千呼万唤始出来,pnpm v10 终于正式发布了。

众所周知,笔者有关注行业技术最新进展的爱好,这次的 pnpm v10 版本,也已经跟踪了好几个月了。

而这次,v10 正式版终于发布了。

版本时间
pnpm 10.02025年01月08日
pnpm 10.0 RC 32025年01月05日
pnpm 10.0 RC 22024年12月29日
pnpm 10.0 RC 12024年12月27日
pnpm 10.0 RC 02024年12月16日
pnpm 10.0 Beta 32024年12月12日
pnpm 10.0 Beta 22024年12月09日
pnpm 10.0 Beta 12024年11月29日
pnpm 10.0 Alpha 42024年11月25日
pnpm 10.0 Alpha 32024年11月25日
pnpm 10.0 Alpha 22024年11月15日
pnpm 10.0 Alpha 12024年11月15日
pnpm 10.0 Alpha 02024年10月08日

以上是笔者整理的 pnpm v10 发布过程,从 草案,到 测试版,到 候选版,再到最后的 正式版,可谓是花了不少功夫啊。

也从侧面说明了,pnpm 团队对这次 v10 版本的重视程度,必然是有大事发生,那么话不多说,我们看看本次的更新内容吧。

依赖项的生命周期脚本不会在安装期间执行

这是一个重要变化,依赖包的 生命周期脚本 不会自动执行了。

那么问题来了,可能有些读者还不知道什么是 生命周期脚本生命周期脚本 英文名叫做 Lifecycle scripts

包括以下几种:

  1. 安装相关脚本
    • preinstall:在安装软件包之前执行。
    • install:在安装软件包时执行。
    • postinstall:在安装软件包之后执行。
  2. 发布相关脚本
    • prepare:在发布软件包之前执行。
    • prepublishOnly:只在 npm publish 时执行。
    • prepack:在打包软件包之前执行。
    • postpack:在打包软件包之后执行。
  3. 运行相关脚本
    • prestart/start/poststart:在运行 npm start 时执行。
    • prerestart/restart/postrestart:在运行 npm restart 时执。
    • prestop/stop/poststop:在运行 npm stop 时执行。
    • pretest/test/posttest:在运行 npm test 时执行。

pnpnm v10 开始,这些依赖包中的生命周期脚本都不会自动执行了,这样可以进一步提高安全性。

投票

官方也发起了一个投票:pnpm 可以在安装期间阻止依赖项的生命周期脚本。但这是一个可选功能。我们应该默认阻止它们吗?

最终赞成禁用生命周期脚本的占大多数。

那么我们要让某些依赖包的脚本可以自动执行的话,应怎么做呢?

json
{
    "pnpm": {
        "onlyBuiltDependencies": ["fsevents"]
    }
}

如上示例,pnpm 提供了一个 onlyBuiltDependencies 参数,所有可以自动执行生命周期脚本的包,都要手动写到里面。

这么一来呢,确实提高了安全性,但是对于开发者来说,也提高了不少复杂性。

因为,可能有些依赖包,或者说依赖包的依赖包,需要自动执行脚本才能生效。

如果采用手动模式,那就很可能很难找到,到底要执行哪个包的生命周期脚本,提高了安全性的同时,也降低了开发的便捷性。

这个可能有很多人还没用过,主要用途有 2 个:

  1. 替换已安装的软件包
    • 当你正在开发一个依赖包,想在另一个项目中测试它时,可以使用 pnpm link 将本地版本链接到目标项目。
    • 这样可以避免频繁地发布和安装依赖包,提高开发效率。
  2. 添加全局可用的二进制文件
    • 如果你开发了一个包含命令行工具的软件包,可以使用 pnpm link 将其二进制文件注册到全局,以便在任何地方都可以执行。
    • 这对于开发 CLI 工具非常有用。

那么这次的主要变化有 2 个。

  1. 通过 pnpm link 默认创建的是全局包,在之前,则需要 pnpm link -g 才可以创建全局包。
  2. workspace 的多包项目中,override 被添加到工作区的根目录,将依赖项链接到工作区中的所有项目。

总而言之,就是能全局的就全局,把影响范围扩大化,免得抠抠搜搜的。

可能有读者不知道 override 是啥,这里也科普一下:

假设项目中有两个依赖 A 和 B,它们都依赖于同一个包 lodash,但是需要使用不同的版本。

那么可以使用 overrides 来指定使用 lodash 的特定版本:

json
{
    "dependencies": {
        "A": "^1.0.0",
        "B": "^2.0.0"
    },
    "pnpm": {
        "overrides": {
            "lodash": "^4.17.21"
        }
    }
}

这样就可以确保项目中使用的 lodash 版本是 4.17.21,而不管 A 和 B 各自需要的版本是什么。

如果某个依赖包存在问题,也可以使用 overrides 来替换它:

json
{
    "dependencies": {
        "problem-package": "^1.0.0"
    },
    "pnpm": {
        "overrides": {
            "problem-package": "my-forked-package@^1.0.1"
        }
    }
}

在这个例子中,我们将 problem-package 替换为 my-forked-package 的 1.0.1 版本。

可能我写的文章稍微啰嗦了点,主要是考虑到读者可能存在不同的经验水平,所以一些概念也扩展科普一下。

使用 SHA256 进行安全哈希处理

各种哈希算法已更新为 SHA256,以增强安全性和一致性:

  • node_modules/.pnpm 内的长路径现在使用 SHA256 进行哈希处理。
  • 锁定文件中的长对等依赖关系哈希现在使用 SHA256 而不是 MD5。
  • pnpm-lock.yamlpackageExtensionsChecksum 字段中存储的哈希现在为 SHA256。
  • 副作用缓存密钥现在使用 SHA256。
  • 锁定文件中的 pnpmfile 校验和现在使用 SHA256。

配置更新

  1. manage-package-manager-versions:默认启用。pnpm 现在默认根据 package.json 中的 packageManager 字段管理自己的版本。
  2. public-hoist-pattern:默认情况下不会提升任何内容。名称中包含 eslintprettier 的包不再提升到 node_modules 的根目录。
  3. 已将 @yarnpkg/extensions 升级至 v2.0.3,这可能会改变您的 pnpm-lock 文件。
  4. virtual-store-dir-max-length:Windows 上的默认值已减少到 60 个字符。
  5. 减少脚本的环境变量:在脚本执行期间,会设置较少的 npm_package_* 环境变量。仅保留 nameversionbinenginesconfig
  6. 即使 NODE_ENV=production,所有依赖项现在都会安装。

从现在开始,NODE_ENV=production 也会安装所有依赖,包括开发依赖,这对于像我这样的强迫症来说,有点难以接受,没有用到的依赖我为啥要安装?

查看官方文档,可以通过 pnpm add --prod 来只安装 dependencies 依赖。

全局存储更新

  1. 全局 store 升级到 v10
  2. 一些注册表允许使用不同的软件包名称或版本发布相同的内容。为了适应这种情况,商店中的索引文件现在使用内容哈希和软件包标识符来存储。
    1. 验证锁文件中的完整性是否与正确的包相对应,在 Git 冲突解决不佳后可能并非如此。
    2. 允许相同的内容被不同的包或者同一个包的不同版本引用。
  3. 更高效的副作用索引。存储中的索引文件结构已更改。现在通过仅列出文件差异而不是所有文件,可以更有效地跟踪副作用。
  4. 新的索引目录存储了包内容映射。以前,这些文件位于文件中。

其他重大变化

  • # 字符现在在 node_modules/.pnpm 内的目录名称中被转义。
  • 运行 pnpm add --global pnpmpnpm add --global @pnpm/exe 现在会失败并出现错误消息,指导您改用 pnpm 自我更新。
  • 通过 URL 添加的依赖项现在在锁文件中记录最终解析的 URL,确保完全捕获任何重定向。
  • pnpm deploy 命令现在仅适用于具有 inject-workspace-packages=true 的工作区。引入此限制是为了让我们能够使用工作区锁定文件为已部署的项目创建适当的锁定文件。
  • 删除了从 lockfile v6v9 的转换。如果您需要 v6v9 的转换,请使用 pnpm CLI v9
  • pnpm test 现在将 test 关键字后的所有参数直接传递给底层脚本。这与 pnpm run test 的行为一致。以前您需要使用 -- 前缀。
  • pnpm deploy 现在尝试从共享锁文件创建专用锁文件以进行部署。如果没有共享锁文件或 force-legacy-deploy 设置为 true,它将回退到没有锁文件的部署。

次要变化

添加了对一种名为 configurational dependencie 的新依赖项类型的支持

这些依赖项在所有其他类型的依赖项之前安装 (在 dependenciesdevDependenciesoptionalDependencies 之前)。

配置依赖项不能具有其自身或生命周期脚本的依赖项,应使用精确版本和完整性校验和添加它们。

示例:

json
{
    "pnpm": {
        "configDependencies": {
            "my-configs": "1.0.0+sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw=="
        }
    }
}

新的 verify-deps-before-run 设置

此设置控制 pnpm 在运行脚本之前如何检查 node_modules,有以下值:

  • install:如果 node_modules 已过时,则自动运行 pnpm install。
  • warn:如果 node_modules 已过时,则打印警告。
  • prompt:如果 node_modules 已过时,则提示用户确认运行 pnpm install。
  • error:如果 node_modules 已过时,则抛出错误。
  • false:禁用依赖性检查。

新的 inject-workspace-packages 设置允许对所有本地工作区依赖项进行硬链接,而不是对其进行符号链接。

以前,这可以使用 dependencyMeta[].injected 来实现,现在仍然受支持。

更快的重复安装

在重复安装时,pnpm 会执行快速检查以确保 node_modules 是最新的。

pnpm add 与默认工作区目录集成

添加依赖项时,pnpm add 会检查默认工作区目录。

如果依赖项和版本要求与目录匹配,pnpm add 将使用 catalog: 协议。

如果没有指定版本,它将匹配目录的版本。

如果不匹配,它将恢复为标准行为。

pnpm dlx 解析调整

pnpm dlx 现在将软件包解析为其确切版本,并将这些确切版本用作缓存键。

这可确保 pnpm dlx 始终安装最新请求的软件包。

node_modules 验证

某些命令没有 node_modules 验证,不应修改 node_modules 的命令 (例如 pnpm install --lockfile-only) 不再验证或清除 node_modules。

以上就是本次 pnpm v10 的更新内容,感谢阅读,欢迎点赞,评论和转发。

👇 往期文章:

何以解忧,唯有代码。不忘初心,方得始终。